﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace DbAccess
{
    internal static class DataConverter
    {
        public static Dictionary<string, object> ConvertToDictionary(this object data)
        {
            var dictionary = new Dictionary<string, object>();
            if (data == null)
                return dictionary;
            if (data is IDictionary<string, object> genericDict)
                return new Dictionary<string, object>(genericDict);
            if (data is IDictionary nonGenericDict)
            {
                foreach (DictionaryEntry entry in nonGenericDict)
                {
                    if (entry.Key == null) continue;
                    string key = entry.Key.ToString();
                    if (!dictionary.ContainsKey(key))
                        dictionary.Add(key, entry.Value);
                }
                return dictionary;
            }
            Type dataType = data.GetType();
            // 检查是否为类或匿名类型，否则抛异常
            if (!IsAllowedTypeForReflection(dataType))
                throw new InvalidOperationException(
                        $"Cannot convert type '{dataType.Name}' to Dictionary. " +
                        "Only classes, anonymous types, and dictionaries are supported."
                    );
            foreach (PropertyInfo property in dataType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                if (!property.CanRead) continue;
                object value = property.GetValue(data, null);
                dictionary[property.Name] = value;
            }
            return dictionary;
        }
        /// <summary>
        /// 检查类型是否允许进行反射转换（类或匿名类型）
        /// </summary>
        private static bool IsAllowedTypeForReflection(Type type)
        {
            bool isAnonymousType =
                type.IsDefined(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), false) &&
                type.Name.Contains("AnonymousType");
            return type.IsClass || isAnonymousType;
        }
    }
}
